import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist

#第一步：读取MNIST数据集使用load_mnist()函数，参数one_hot_label=True得到one-hot表示（即正确标签为1，其余为0的数据结构）
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=False)
#训练数据有60000个，784维的图像数据（28*28）
print('x_train.shape: ' + str(x_train.shape))
#监督数据有60000个，10维的数据
print('t_train.shape: ' + str(t_train.shape))
print('提取前3条监督数据，此时one_hot_label=False')
t = t_train[0:3]
print(t)


#第二步：从训练数据中随机抽取10笔数据，使用np.random.choice()方法
train_size = x_train.shape[0]
batch_size = 10
#从0到59999（train_size）之间随机选择10（batch_size）个数字
batch_mask = np.random.choice(train_size, batch_size)
#通过随机选出的索引batch_mask，取出mini-batch
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]

#第三步，定义交叉熵误差函数
#当one_hot_label=True的情况下，监督数据是1和0的形式
def cross_entropy_error_one_hot(y, t):  #y是神经网络的输出，t是监督数据
    #首先判断并处理输入数据是单个数据和batch批量数据两种情况
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

#当one_hot_label=False的情况下，监督数据是标签类型形式
def cross_entropy_error_not_one_hot(y, t):
    if y.ndim ==1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

#以MINST的前5条监督数据为例进行交叉熵计算,t_one_hot为one_hot_label=True时的数据，t_not_one_hot为one_hot_label=False时的数据
t_one_hot = np.array([[0, 0, 0, 0, 0, 1, 0, 0, 0, 0,], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0,]])
t_not_one_hot = np.array([5, 0, 4])
y = np.array([[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0], [0.1, 0.05, 0.0, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.6], [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]])

print(cross_entropy_error_one_hot(y, t_one_hot))

print(cross_entropy_error_not_one_hot(y, t_not_one_hot))
